import treeJsonSchema from "./tree-json-schema.js";
import { emptyObject } from "./object.js";
import recast from "recast";
// 需要定时更新
/**
 * 生成API接口层代码
 * @param {Api} api
 * @returns {string|*}
 */
export const generateApiCode = function (api, detail) {
  /**
   * 生成标准jsonSchema结构
   * @param args
   */
  const generateJsonSchemaString = function (...args) {
    const schema = Object.assign(
      {},
      {
        id: "http://json-schema.org/draft-04/schema#",
        $schema: "http://json-schema.org/draft-04/schema#",
        title: api.name,
        description: api.description,
      },
      ...args
    );

    if (schema.type === "object" && emptyObject(schema.properties)) {
      return;
    }

    if (schema.type === "array" && schema.items && schema.items.length) {
      return;
    }

    return JSON.stringify(schema);
  };

  /**
   * 名字和别名翻转
   * @param {Object} item
   * @return {*}
   */
  const nameEvertAlias = (item) => {
    // 转换请求参数时，网关名和参数名对调，使输出名等于网关名
    let alias = item.alias;
    item.alias = item.name;
    item.name = alias;
    return item;
  };

  /**
   * 把请求头转换可描述对象
   * @type {string}
   */
  const headerParamsSchemaString = generateJsonSchemaString(
    {
      title: "Header",
      description: "",
    },
    new treeJsonSchema("object", api.heeder_params, nameEvertAlias)
  );

  /**
   * 把查询参数转换可描述对象
   * @type {string}
   */
  const queryParamsSchemaString = generateJsonSchemaString(
    {
      title: "Query",
      description: "",
    },
    new treeJsonSchema("object", api.query_params, nameEvertAlias)
  );

  /**
   * 把请求参数转换为可描述对象
   * @type {string}
   */
  const requestParamsSchemaString = generateJsonSchemaString(
    new treeJsonSchema(
      api.body_params_root_type,
      api.body_params,
      nameEvertAlias
    )
  );

  /**
   * 把响应参数转换可描述对象
   * @type {string}
   */
  const responseDataSchemaString = generateJsonSchemaString(
    new treeJsonSchema(api.response_params_root_type, api.response_params)
  );

  /**
   * 模板参数
   * @type {Object}
   */
  const params = {
    api: api.number_no,
    apiPath: api.url,
    moduleName: api.module_name,
    apiAlias: api.alias,
    headerParamsSchema: headerParamsSchemaString,
    queryParamsSchema: queryParamsSchemaString,
    requestParamsSchema: requestParamsString(api, detail),
    responseDataSchema: responesParamsString(api, detail),
    redundancy: api.redundancy,
  };

function requestParamsString(api, detail) {
  const param = {
    id: "http://json-schema.org/draft-04/schema#",
    $schema: "http://json-schema.org/draft-04/schema#",
    title: api.name,
    description: api.description,
    type: detail.body_params_root_type
  }
  if (param.type === 'object') {
    param.properties = {};
    param.required = [];
    recursion(param.properties, detail.body_params, param.required);
  }
  return JSON.stringify(param);
}

function responesParamsString(api, detail) {
  const hasResp = detail.response_params.filter((item) => item.name.length > 0).length > 0;
  if (hasResp === false) {
    return ' undefined, ' + JSON.stringify({
      redundancy: detail.redundancy
    });
  }
  const param = {
    id: "http://json-schema.org/draft-04/schema#",
    $schema: "http://json-schema.org/draft-04/schema#",
    title: api.name,
    description: api.description,
    type: detail.response_params_root_type
  }
  if (param.type === 'object') {
    param.properties = {};
    param.required = [];
    recursion(param.properties, detail.response_params, param.required);
  }
  return JSON.stringify(param) + ' , ' + JSON.stringify({
    redundancy: detail.redundancy
  });
}

function recursion(properties, params, appendRequired) {
  const required = [];
  for (const param of params) {
    if (!param.name) {
      continue;
    }
    const p = {
      type: param.type,
      required: param.required,
    };

    if (param.default !== undefined) {
      p.default = param.default;
    }
    if (param.enums.length > 0) {
      p['@enums'] = param.enums.map((item) => {
        return {
          type: item.type,
          name: item.name,
          value: item.value
        }
      });
    }
    
    if (p.type === 'object') {
      p.properties = {};
    } else if (p.type === 'array') {
      p.items = {
        type: 'object',
        required: [],
        properties: {}
      };
    }

    p['@alias'] = param.name;
    p['@name'] = param.alias;

    if (properties.properties) {
      properties.properties[param.name] = p;
    } else {
      properties[param.name] = p;
    }
    
    param.required && required.push(param.name);
    if (param.children.length <= 0) {
      continue;
    }
    recursion(p.items || p, param.children);
  }

  if (Array.isArray(appendRequired)) {
    appendRequired.push(...required);
  } else if (Array.isArray(properties.required)) {
    properties.required.push(...required);
  } else {
    properties.required = required;
  }
}

const code = `/* eslint-disable */


(function() {
    var factory = function(getters) {
        var api = getters[0](), APIModule = getters[1](), apiNameAndEnumConvert2 = getters[2](), apiOptions = getters[3]();
        var moduleName = "${params.moduleName}", 
        apiAlias = "${params.apiAlias}";

        var apiDefinition = {
            api: "${params.apiPath}",
            method: "POST",
            apiAlias: apiAlias,
            apiModuleName: moduleName,

            requestHeadersNameAndEnumMapMethod: function(api, headers) {
                return apiNameAndEnumConvert2(headers, ${params.headerParamsSchema});
            },

            requestQueriesNameAndEnumMapMethod: function(api, queries) {
                return apiNameAndEnumConvert2(queries, ${params.queryParamsSchema});
            },

            requestParamsNameAndEnumMapMethod: function(api, params) {
                return apiNameAndEnumConvert2(params, ${params.requestParamsSchema});
            },

            responseDataNameAndEnumMapMethod: function(api, data) {
                return apiNameAndEnumConvert2(data, ${params.responseDataSchema});
            }
        };

        if (null != apiOptions) {
            for (var p in apiOptions) {
                apiDefinition[p] = apiOptions[p];
            }

            api.defineApi(apiDefinition);
        }

        return function(ops) {
            APIModule.ofName(moduleName).callApi(apiAlias, ops);
        };
    };

    var defineModule = new Function("return this")().defineModule;
    var pluginName = "nl:${params.moduleName}/${params.apiAlias}";

    if (typeof define === "function") {
        define([
            "@youlu/niceloo/libs/@xlib.01/niceloo/apiserver/api.js",
            "@youlu/niceloo/libs/@xlib.01/niceloo/apiserver/APIModule.js",
            "@youlu/niceloo/libs/@xlib.01/lib/apiNameAndEnumConvert2.js",
            "./api.${params.api}.${params.apiAlias}.options.js"
        ], function() {
            if (typeof defineModule === "function") {
                return defineModule.wrap4amdjs(pluginName, arguments, factory);
            } else {
                return factory(Array.prototype.map.call(arguments, function(r) {
                    return function() {
                        return r;
                    };
                }));
            }
        });
    } else if (typeof defineModule === "function") {
        defineModule(pluginName, [
            "nl:apiserver.api=@youlu/niceloo/libs/@xlib.01/niceloo/apiserver/api.js",
            "nl:apiserver.APIModule=@youlu/niceloo/libs/@xlib.01/niceloo/apiserver/APIModule.js",
            "apiNameAndEnumConvert2=@youlu/niceloo/libs/@xlib.01/lib/apiNameAndEnumConvert2.js",
            "nl:${params.moduleName}/${params.apiAlias}$options=./api.${params.api}.${params.apiAlias}.options.js"
        ], factory, defineModule.isEnvNode() ? {
            module: module
        } : null);
    }
})();`;
  const node = recast.parse(code);
  return recast.prettyPrint(node).code;
};

/**
 * 生成文件名
 * @param api
 * @return {string}
 */
 export const generateApiFilename = (api) =>
 `api.${ api.number_no }.${ api.alias }.js`;

